/***************************************************
*@Author       : fairy
*@Date         : 2021-09-17 10:56:34
*@LastEditors  : fairy
*@LastEditTime : 2021-10-15 10:55:22
*@FilePath     : LCD1602.c
***************************************************/
#include "LCD1602.h"

/***************************************************
*@description  : 判断1602液晶忙，并等待
*@param         {*}
*@return        {*}
***************************************************/
void Read_Busy(void)
{
	/*
	基本操作时序：
	1.1 读状态：
		输入：RS = L，RW = H，E = H
		输出：D0 ~ D7 = 状态字
	*/
	unsigned char busy;
	LCD1602_DB = 0xff;      //复位数据总线
	LCD1602_RS = 0;	        //拉低RS
	LCD1602_RW = 1;	        //拉高RW读
	do
	{
		LCD1602_EN = 1;     //使能EN
		busy = LCD1602_DB;  //读回数据
		LCD1602_EN = 0;	    //拉低使能以便于下一次产生上升沿
	}while(busy & 0x80);    //判断状态字BIT7位是否为1，为1则表示忙，程序等待
}

/***************************************************
*@description  : 写LCD1602指令
*@param         {unsigned char} cmd 要写的指令
*@return        {*}
***************************************************/
void LCD1602_Write_Cmd(unsigned char cmd)
{
	/*
	基本操作时序：
	1.2 写指令：
		输入：RS = L，RW = L，D0~D7 = 指令码，E = 高脉冲
		输出：无
	*/
	Read_Busy();	    //判断忙，忙则等待
	LCD1602_RS = 0;
	LCD1602_RW = 0;	    //拉低RS、RW操作时序情况1602课件下中文使用说明基本操作时序章节
	LCD1602_DB = cmd;   //写入指令
	LCD1602_EN = 1;	    //拉高使能端 数据被传输到LCD1602内
	LCD1602_EN = 0;	    //拉低使能以便于下一次产生上升沿
}

/***************************************************
*@description  : 写LCD1602数据
*@param         {unsigned char} dat 需要写入的数据
*@return        {*}
***************************************************/
void LCD1602_Write_Dat(unsigned char dat)
{
	/*
	基本操作时序：
	1.2 写指令：
		输入：RS = H，RW = L，D0~D7 = 数据，E = 高脉冲
		输出：无
	*/
	Read_Busy();        //判断忙，忙则等待
	LCD1602_RS = 1;
	LCD1602_RW = 0;
	LCD1602_DB = dat;   //写入数据
	LCD1602_EN = 1;     //拉高使能端 数据被传输到LCD1602内
	LCD1602_EN = 0;     //拉低使能以便于下一次产生上升沿
}

/***************************************************
*@description  : 在指定位置显示一个字符
*@param         {unsigned char} x 要显示的横坐标，取值0-40
*@param         {unsigned char} y 要显示的行坐标，取值0-1（0为第一行,1为第二行）
*@param         {unsigned char} dat 需要显示的数据，以ASCLL形式显示
*@return        {*}
***************************************************/
void LCD1602_Dis_OneChar(unsigned char x, unsigned char y,unsigned char dat)
{

	if(y)
	{
		// 显示在第2行
		x |= 0x40;
	}
	x |= 0x80;
	
	LCD1602_Write_Cmd(x);		// 数据指针设置，指向待写入的位置
	LCD1602_Write_Dat(dat);		// 写数据
}

/***************************************************
*@description  : 在指定位置显示字符串
*@param         {unsigned char} x 要显示的横坐标，取值0-40
*@param         {unsigned char} y 要显示的行坐标，取值0-1（0为第一行,1为第二行）
*@param         {unsigned char} *str 需要显示的字符串
*@return        {*}
***************************************************/
void LCD1602_Dis_Str(unsigned char x, unsigned char y, unsigned char *str)
{
	if(y)
	{
		// 显示在第2行
		x |= 0x40;
	}
	x |= 0x80;

	LCD1602_Write_Cmd(x);
	while(*str != '\0')
	{
		LCD1602_Write_Dat(*str++);
	}
}

/***************************************************
*@description  : 1602初始化
*@param         {*}
*@return        {*}
***************************************************/
void Init_LCD1602(void)
{
	LCD1602_Write_Cmd(0x38); //设置16*2显示，5*7点阵，8位数据接口
	LCD1602_Write_Cmd(0x0c); //开显示、不显示光标、光标不闪烁
	LCD1602_Write_Cmd(0x06); //读写一字节后地址指针加1、整屏显示不移动
	LCD1602_Write_Cmd(0x01); //清除显示
}
/*
1602指令码
1、初始化设置
1.1、显示模式设置
	指令码	功能
	0x38	设置16*2显示，5*7点阵，8位数据接口
1.2、显示开/关及光标设置
	指令码		指令	功能
	0000 1DCB	0x0f	开显示、显示光标、光标闪烁
				0x0e	开显示、显示光标、光标不闪烁
				0x0c	开显示、不显示光标、光标不闪烁
				0x08	关开显示、不显示光标、光标不闪烁【显示关闭】
				

	0000 01NS			N = 1：当读或写一个字符后地址指针加一，且光标加一
						N = 0；当读或写一个字符后地址指针减一，且光标减一
						S = 1：当写一个字符，整屏显示左移（N=1）或者右移（N=0），得到光标不移动而屏幕移动的效果
						S = 0：当写一个字符，整屏显示不移动
2、数据控制
2.1、数据指令设置
	指令码								功能
	80H+地址码（范围0-27H，40H-67H）	设置数据地址指针
2.2、读数据
2.3、写数据
2.4、其他设置
	指令码		功能
	01H			显示清屏：数据指针清零、所有显示清零
	02H			显示回车：数据指针清零
*/
